home *** CD-ROM | disk | FTP | other *** search
/ Aminet 30 / Aminet 30 (1999)(Schatztruhe)[!][Apr 1999].iso / Aminet / gfx / misc / gnuplot-3.7src.lha / gnuplot-3.7src / gnuplot-3.7.lha / gnuplot-3.7 / util.c < prev    next >
C/C++ Source or Header  |  1998-12-09  |  15KB  |  657 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: util.c,v 1.46 1998/06/18 14:55:20 ddenholm Exp $";
  3. #endif
  4.  
  5. /* GNUPLOT - util.c */
  6.  
  7. /*[
  8.  * Copyright 1986 - 1993, 1998   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted,
  12.  * provided that the above copyright notice appear in all copies and
  13.  * that both that copyright notice and this permission notice appear
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the complete modified source code.  Modifications are to
  18.  * be distributed as patches to the released version.  Permission to
  19.  * distribute binaries produced by compiling modified sources is granted,
  20.  * provided you
  21.  *   1. distribute the corresponding source modifications from the
  22.  *    released version in the form of a patch file along with the binaries,
  23.  *   2. add special version identification to distinguish your version
  24.  *    in addition to the base release version number,
  25.  *   3. provide your name and address as the primary contact for the
  26.  *    support of your modified version, and
  27.  *   4. retain our contact information in regard to use of the base
  28.  *    software.
  29.  * Permission to distribute the released version of the source code along
  30.  * with corresponding source modifications in the form of a patch file is
  31.  * granted with same provisions 2 through 4 for binary distributions.
  32.  *
  33.  * This software is provided "as is" without express or implied warranty
  34.  * to the extent permitted by applicable law.
  35. ]*/
  36.  
  37.  
  38. #include "plot.h"
  39. #include "setshow.h"        /* for month names etc */
  40.  
  41.  
  42. /* TRUE if command just typed; becomes FALSE whenever we
  43.  * send some other output to screen.  If FALSE, the command line
  44.  * will be echoed to the screen before the ^ error message.
  45.  */
  46. TBOOLEAN screen_ok;
  47.  
  48. static char *num_to_str __PROTO((double r));
  49. static void parse_esc __PROTO((char *instr));
  50.  
  51. /*
  52.  * chr_in_str() compares the characters in the string of token number t_num
  53.  * with c, and returns TRUE if a match was found.
  54.  */
  55. int chr_in_str(t_num, c)
  56. int t_num;
  57. int c;
  58. {
  59.     register int i;
  60.  
  61.     if (!token[t_num].is_token)
  62.     return (FALSE);        /* must be a value--can't be equal */
  63.     for (i = 0; i < token[t_num].length; i++) {
  64.     if (input_line[token[t_num].start_index + i] == c)
  65.         return (TRUE);
  66.     }
  67.     return FALSE;
  68. }
  69.  
  70.  
  71. /*
  72.  * equals() compares string value of token number t_num with str[], and
  73.  *   returns TRUE if they are identical.
  74.  */
  75. int equals(t_num, str)
  76. int t_num;
  77. char *str;
  78. {
  79.     register int i;
  80.  
  81.     if (!token[t_num].is_token)
  82.     return (FALSE);        /* must be a value--can't be equal */
  83.     for (i = 0; i < token[t_num].length; i++) {
  84.     if (input_line[token[t_num].start_index + i] != str[i])
  85.         return (FALSE);
  86.     }
  87.     /* now return TRUE if at end of str[], FALSE if not */
  88.     return (str[i] == NUL);
  89. }
  90.  
  91.  
  92.  
  93. /*
  94.  * almost_equals() compares string value of token number t_num with str[], and
  95.  *   returns TRUE if they are identical up to the first $ in str[].
  96.  */
  97. int almost_equals(t_num, str)
  98. int t_num;
  99. char *str;
  100. {
  101.     register int i;
  102.     register int after = 0;
  103.     register int start = token[t_num].start_index;
  104.     register int length = token[t_num].length;
  105.  
  106.     if (!token[t_num].is_token)
  107.     return (FALSE);        /* must be a value--can't be equal */
  108.     for (i = 0; i < length + after; i++) {
  109.     if (str[i] != input_line[start + i]) {
  110.         if (str[i] != '$')
  111.         return (FALSE);
  112.         else {
  113.         after = 1;
  114.         start--;    /* back up token ptr */
  115.         }
  116.     }
  117.     }
  118.  
  119.     /* i now beyond end of token string */
  120.  
  121.     return (after || str[i] == '$' || str[i] == NUL);
  122. }
  123.  
  124.  
  125.  
  126. int isstring(t_num)
  127. int t_num;
  128. {
  129.  
  130.     return (token[t_num].is_token &&
  131.         (input_line[token[t_num].start_index] == '\'' ||
  132.          input_line[token[t_num].start_index] == '"'));
  133. }
  134.  
  135.  
  136. int isanumber(t_num)
  137. int t_num;
  138. {
  139.     return (!token[t_num].is_token);
  140. }
  141.  
  142.  
  143. int isletter(t_num)
  144. int t_num;
  145. {
  146.     return (token[t_num].is_token &&
  147.         ((isalpha((int)input_line[token[t_num].start_index])) ||
  148.          (input_line[token[t_num].start_index] == '_')));
  149. }
  150.  
  151.  
  152. /*
  153.  * is_definition() returns TRUE if the next tokens are of the form
  154.  *   identifier =
  155.  *              -or-
  156.  *   identifier ( identifer {,identifier} ) =
  157.  */
  158. int is_definition(t_num)
  159. int t_num;
  160. {
  161.     /* variable? */
  162.     if (isletter(t_num) && equals(t_num + 1, "="))
  163.     return 1;
  164.  
  165.     /* function? */
  166.     /* look for dummy variables */
  167.     if (isletter(t_num) && equals(t_num + 1, "(") && isletter(t_num + 2)) {
  168.     t_num += 3;        /* point past first dummy */
  169.     while (equals(t_num, ",")) {
  170.         if (!isletter(++t_num))
  171.         return 0;
  172.         t_num += 1;
  173.     }
  174.     return (equals(t_num, ")") && equals(t_num + 1, "="));
  175.     }
  176.     /* neither */
  177.     return 0;
  178. }
  179.  
  180.  
  181.  
  182. /*
  183.  * copy_str() copies the string in token number t_num into str, appending
  184.  *   a null.  No more than max chars are copied (including \0).
  185.  */
  186. void copy_str(str, t_num, max)
  187. char str[];
  188. int t_num;
  189. int max;
  190. {
  191.     register int i = 0;
  192.     register int start = token[t_num].start_index;
  193.     register int count;
  194.  
  195.     if ((count = token[t_num].length) >= max) {
  196.     count = max - 1;
  197.     FPRINTF((stderr, "str buffer overflow in copy_str"));
  198.     }
  199.     do {
  200.     str[i++] = input_line[start++];
  201.     } while (i != count);
  202.     str[i] = NUL;
  203. }
  204.  
  205. /* length of token string */
  206. int token_len(t_num)
  207. int t_num;
  208. {
  209.     return (token[t_num].length);
  210. }
  211.  
  212. /*
  213.  * quote_str() does the same thing as copy_str, except it ignores the
  214.  *   quotes at both ends.  This seems redundant, but is done for
  215.  *   efficency.
  216.  */
  217. void quote_str(str, t_num, max)
  218. char str[];
  219. int t_num;
  220. int max;
  221. {
  222.     register int i = 0;
  223.     register int start = token[t_num].start_index + 1;
  224.     register int count;
  225.  
  226.     if ((count = token[t_num].length - 2) >= max) {
  227.     count = max - 1;
  228.     FPRINTF((stderr, "str buffer overflow in quote_str"));
  229.     }
  230.     if (count > 0) {
  231.     do {
  232.         str[i++] = input_line[start++];
  233.     } while (i != count);
  234.     }
  235.     str[i] = NUL;
  236.     /* convert \t and \nnn (octal) to char if in double quotes */
  237.     if (input_line[token[t_num].start_index] == '"')
  238.     parse_esc(str);
  239. }
  240.  
  241.  
  242. /*
  243.  * capture() copies into str[] the part of input_line[] which lies between
  244.  * the begining of token[start] and end of token[end].
  245.  */
  246. void capture(str, start, end, max)
  247. char str[];
  248. int start, end;
  249. int max;
  250. {
  251.     register int i, e;
  252.  
  253.     e = token[end].start_index + token[end].length;
  254.     if (e - token[start].start_index >= max) {
  255.     e = token[start].start_index + max - 1;
  256.     FPRINTF((stderr, "str buffer overflow in capture"));
  257.     }
  258.     for (i = token[start].start_index; i < e && input_line[i] != NUL; i++)
  259.     *str++ = input_line[i];
  260.     *str = NUL;
  261. }
  262.  
  263.  
  264. /*
  265.  * m_capture() is similar to capture(), but it mallocs storage for the
  266.  * string.
  267.  */
  268. void m_capture(str, start, end)
  269. char **str;
  270. int start, end;
  271. {
  272.     register int i, e;
  273.     register char *s;
  274.  
  275.     if (*str)            /* previous pointer to malloc'd memory there */
  276.     free(*str);
  277.     e = token[end].start_index + token[end].length;
  278.     *str = gp_alloc((unsigned long) (e - token[start].start_index + 1), "string");
  279.     s = *str;
  280.     for (i = token[start].start_index; i < e && input_line[i] != NUL; i++)
  281.     *s++ = input_line[i];
  282.     *s = NUL;
  283. }
  284.  
  285.  
  286. /*
  287.  *    m_quote_capture() is similar to m_capture(), but it removes
  288.  quotes from either end if the string.
  289.  */
  290. void m_quote_capture(str, start, end)
  291. char **str;
  292. int start, end;
  293. {
  294.     register int i, e, escflag = 0;
  295.     register char *s;
  296.  
  297.     if (*str)            /* previous pointer to malloc'd memory there */
  298.     free(*str);
  299.     e = token[end].start_index + token[end].length - 1;
  300.     *str = gp_alloc((unsigned long) (e - token[start].start_index + 1), "string");
  301.     s = *str;
  302.     for (i = token[start].start_index + 1; i < e && input_line[i] != NUL; i++)
  303.     if ((*s++ = input_line[i]) == '\\') ++escflag;
  304.     *s = NUL;
  305.     if (escflag) parse_esc(*str);
  306. }
  307.  
  308.  
  309. void convert(val_ptr, t_num)
  310. struct value *val_ptr;
  311. int t_num;
  312. {
  313.     *val_ptr = token[t_num].l_val;
  314. }
  315.  
  316. static char *num_to_str(r)
  317. double r;
  318. {
  319.     static int i = 0;
  320.     static char s[4][25];
  321.     int j = i++;
  322.  
  323.     if (i > 3)
  324.     i = 0;
  325.  
  326.     sprintf(s[j], "%.15g", r);
  327.     if (strchr(s[j], '.') == NULL &&
  328.     strchr(s[j], 'e') == NULL &&
  329.     strchr(s[j], 'E') == NULL)
  330.     strcat(s[j], ".0");
  331.  
  332.     return s[j];
  333. }
  334.  
  335. void disp_value(fp, val)
  336. FILE *fp;
  337. struct value *val;
  338. {
  339.     switch (val->type) {
  340.     case INTGR:
  341.     fprintf(fp, "%d", val->v.int_val);
  342.     break;
  343.     case CMPLX:
  344.     if (val->v.cmplx_val.imag != 0.0)
  345.         fprintf(fp, "{%s, %s}",
  346.             num_to_str(val->v.cmplx_val.real),
  347.             num_to_str(val->v.cmplx_val.imag));
  348.     else
  349.         fprintf(fp, "%s",
  350.             num_to_str(val->v.cmplx_val.real));
  351.     break;
  352.     default:
  353.     int_error("unknown type in disp_value()", NO_CARET);
  354.     }
  355. }
  356.  
  357.  
  358. double real(val)        /* returns the real part of val */
  359. struct value *val;
  360. {
  361.     switch (val->type) {
  362.     case INTGR:
  363.     return ((double) val->v.int_val);
  364.     case CMPLX:
  365.     return (val->v.cmplx_val.real);
  366.     }
  367.     int_error("unknown type in real()", NO_CARET);
  368.     /* NOTREACHED */
  369.     return ((double) 0.0);
  370. }
  371.  
  372.  
  373. double imag(val)        /* returns the imag part of val */
  374. struct value *val;
  375. {
  376.     switch (val->type) {
  377.     case INTGR:
  378.     return (0.0);
  379.     case CMPLX:
  380.     return (val->v.cmplx_val.imag);
  381.     }
  382.     int_error("unknown type in imag()", NO_CARET);
  383.     /* NOTREACHED */
  384.     return ((double) 0.0);
  385. }
  386.  
  387.  
  388.  
  389. double magnitude(val)        /* returns the magnitude of val */
  390. struct value *val;
  391. {
  392.     switch (val->type) {
  393.     case INTGR:
  394.     return ((double) abs(val->v.int_val));
  395.     case CMPLX:
  396.     return (sqrt(val->v.cmplx_val.real *
  397.              val->v.cmplx_val.real +
  398.              val->v.cmplx_val.imag *
  399.              val->v.cmplx_val.imag));
  400.     }
  401.     int_error("unknown type in magnitude()", NO_CARET);
  402.     /* NOTREACHED */
  403.     return ((double) 0.0);
  404. }
  405.  
  406.  
  407.  
  408. double angle(val)        /* returns the angle of val */
  409. struct value *val;
  410. {
  411.     switch (val->type) {
  412.     case INTGR:
  413.     return ((val->v.int_val >= 0) ? 0.0 : Pi);
  414.     case CMPLX:
  415.     if (val->v.cmplx_val.imag == 0.0) {
  416.         if (val->v.cmplx_val.real >= 0.0)
  417.         return (0.0);
  418.         else
  419.         return (Pi);
  420.     }
  421.     return (atan2(val->v.cmplx_val.imag,
  422.               val->v.cmplx_val.real));
  423.     }
  424.     int_error("unknown type in angle()", NO_CARET);
  425.     /* NOTREACHED */
  426.     return ((double) 0.0);
  427. }
  428.  
  429.  
  430. struct value *
  431.  Gcomplex(a, realpart, imagpart)
  432. struct value *a;
  433. double realpart, imagpart;
  434. {
  435.     a->type = CMPLX;
  436.     a->v.cmplx_val.real = realpart;
  437.     a->v.cmplx_val.imag = imagpart;
  438.     return (a);
  439. }
  440.  
  441.  
  442. struct value *
  443.  Ginteger(a, i)
  444. struct value *a;
  445. int i;
  446. {
  447.     a->type = INTGR;
  448.     a->v.int_val = i;
  449.     return (a);
  450. }
  451.  
  452.  
  453. void os_error(str, t_num)
  454. char str[];
  455. int t_num;
  456. {
  457. #ifdef VMS
  458.     static status[2] =
  459.     {1, 0};            /* 1 is count of error msgs */
  460. #endif /* VMS */
  461.  
  462.     register int i;
  463.  
  464.     /* reprint line if screen has been written to */
  465.  
  466.     if (t_num != NO_CARET) {    /* put caret under error */
  467.     if (!screen_ok)
  468.         fprintf(stderr, "\n%s%s\n", PROMPT, input_line);
  469.  
  470.     for (i = 0; i < sizeof(PROMPT) - 1; i++)
  471.         (void) putc(' ', stderr);
  472.     for (i = 0; i < token[t_num].start_index; i++) {
  473.         (void) putc((input_line[i] == '\t') ? '\t' : ' ', stderr);
  474.     }
  475.     (void) putc('^', stderr);
  476.     (void) putc('\n', stderr);
  477.     }
  478.     for (i = 0; i < sizeof(PROMPT) - 1; i++)
  479.     (void) putc(' ', stderr);
  480.     fputs(str, stderr);
  481.     putc('\n', stderr);
  482.  
  483.     for (i = 0; i < sizeof(PROMPT) - 1; i++)
  484.     (void) putc(' ', stderr);
  485.     if (!interactive) {
  486.     if (infile_name != NULL)
  487.         fprintf(stderr, "\"%s\", line %d: ", infile_name, inline_num);
  488.     else
  489.         fprintf(stderr, "line %d: ", inline_num);
  490.     }
  491.  
  492.  
  493. #ifdef VMS
  494.     status[1] = vaxc$errno;
  495.     sys$putmsg(status);
  496.     (void) putc('\n', stderr);
  497. #else /* VMS */
  498.     fprintf(stderr, "(%s)\n\n", strerror(errno));
  499. #endif /* VMS */
  500.  
  501.     bail_to_command_line();
  502. }
  503.  
  504.  
  505. void int_error(str, t_num)
  506. char str[];
  507. int t_num;
  508. {
  509.     register int i;
  510.  
  511.     /* reprint line if screen has been written to */
  512.  
  513.     if (t_num != NO_CARET) {    /* put caret under error */
  514.     if (!screen_ok)
  515.         fprintf(stderr, "\n%s%s\n", PROMPT, input_line);
  516.  
  517.     for (i = 0; i < sizeof(PROMPT) - 1; i++)
  518.         (void) putc(' ', stderr);
  519.     for (i = 0; i < token[t_num].start_index; i++) {
  520.         (void) putc((input_line[i] == '\t') ? '\t' : ' ', stderr);
  521.     }
  522.     (void) putc('^', stderr);
  523.     (void) putc('\n', stderr);
  524.     }
  525.     for (i = 0; i < sizeof(PROMPT) - 1; i++)
  526.     (void) putc(' ', stderr);
  527.     if (!interactive) {
  528.     if (infile_name != NULL)
  529.         fprintf(stderr, "\"%s\", line %d: ", infile_name, inline_num);
  530.     else
  531.         fprintf(stderr, "line %d: ", inline_num);
  532.     }
  533.     fputs(str, stderr);
  534.     fputs("\n\n", stderr);
  535.  
  536.     bail_to_command_line();
  537. }
  538.  
  539. /* Warn without bailing out to command line. Not a user error */
  540. void int_warn(str, t_num)
  541. char str[];
  542. int t_num;
  543. {
  544.     register int i;
  545.  
  546.     /* reprint line if screen has been written to */
  547.  
  548.     if (t_num != NO_CARET) {    /* put caret under error */
  549.     if (!screen_ok)
  550.         fprintf(stderr, "\n%s%s\n", PROMPT, input_line);
  551.  
  552.     for (i = 0; i < sizeof(PROMPT) - 1; i++)
  553.         (void) putc(' ', stderr);
  554.     for (i = 0; i < token[t_num].start_index; i++) {
  555.         (void) putc((input_line[i] == '\t') ? '\t' : ' ', stderr);
  556.     }
  557.     (void) putc('^', stderr);
  558.     (void) putc('\n', stderr);
  559.     }
  560.     for (i = 0; i < sizeof(PROMPT) - 1; i++)
  561.     (void) putc(' ', stderr);
  562.     if (!interactive) {
  563.     if (infile_name != NULL)
  564.         fprintf(stderr, "\"%s\", line %d: ", infile_name, inline_num);
  565.     else
  566.         fprintf(stderr, "line %d: ", inline_num);
  567.     }
  568.     fprintf(stderr, "warning: %s\n", str);
  569.  
  570. }                /* int_warn */
  571.  
  572. /* Lower-case the given string (DFK) */
  573. /* Done in place. */
  574. void lower_case(s)
  575. char *s;
  576. {
  577.     register char *p = s;
  578.  
  579.     while (*p != NUL) {
  580.     if (isupper((int)*p))
  581.         *p = tolower(*p);
  582.     p++;
  583.     }
  584. }
  585.  
  586. /* Squash spaces in the given string (DFK) */
  587. /* That is, reduce all multiple white-space chars to single spaces */
  588. /* Done in place. */
  589. void squash_spaces(s)
  590. char *s;
  591. {
  592.     register char *r = s;    /* reading point */
  593.     register char *w = s;    /* writing point */
  594.     TBOOLEAN space = FALSE;    /* TRUE if we've already copied a space */
  595.  
  596.     for (w = r = s; *r != NUL; r++) {
  597.     if (isspace((int)*r)) {
  598.         /* white space; only copy if we haven't just copied a space */
  599.         if (!space) {
  600.         space = TRUE;
  601.         *w++ = ' ';
  602.         }            /* else ignore multiple spaces */
  603.     } else {
  604.         /* non-space character; copy it and clear flag */
  605.         *w++ = *r;
  606.         space = FALSE;
  607.     }
  608.     }
  609.     *w = NUL;            /* null terminate string */
  610. }
  611.  
  612.  
  613. static void parse_esc(instr)
  614. char *instr;
  615. {
  616.     char *s = instr, *t = instr;
  617.  
  618.     /* the string will always get shorter, so we can do the
  619.      * conversion in situ
  620.      */
  621.  
  622.     while (*s != NUL) {
  623.     if (*s == '\\') {
  624.         s++;
  625.         if (*s == '\\') {
  626.         *t++ = '\\';
  627.         s++;
  628.         } else if (*s == 'n') {
  629.         *t++ = '\n';
  630.         s++;
  631.         } else if (*s == 'r') {
  632.         *t++ = '\r';
  633.         s++;
  634.         } else if (*s == 't') {
  635.         *t++ = '\t';
  636.         s++;
  637.         } else if (*s == '\"') {
  638.         *t++ = '\"';
  639.         s++;
  640.         } else if (*s >= '0' && *s <= '7') {
  641.         int i, n;
  642.         if (sscanf(s, "%o%n", &i, &n) > 0) {
  643.             *t++ = i;
  644.             s += n;
  645.         } else {
  646.             /* int_error("illegal octal number ", c_token); */
  647.             *t++ = '\\';
  648.             *t++ = *s++;
  649.         }
  650.         }
  651.     } else {
  652.         *t++ = *s++;
  653.     }
  654.     }
  655.     *t = NUL;
  656. }
  657.